package pl.edu.pk.cc.server.main;

import java.util.Hashtable;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Vector;

import org.jboss.logging.Logger;

import pl.edu.pk.cc.common.dto.CCLoginDataDTO;
import pl.edu.pk.cc.common.util.CCSession;

public class CCServerSessionsManager {

	private static final int timeoutTime = 3600000;// 1 hour timeout
	private static Logger logg = Logger.getLogger(CCServerSessionsManager.class);
	private static Hashtable<Long, Long> sessionsMap;
	// private static Hashtable<Long, CCPermissions> permissionsMap; // TODO is this needed?
	private static Hashtable<Long, Boolean> timeoutMap;
	private static Timer timeout;
	private static long lastSessionID;

	public synchronized static void init() {
		lastSessionID = 1;
		sessionsMap = new Hashtable<>();
		// permissionsMap = new Hashtable<>();
		timeoutMap = new Hashtable<>();
		timeout = new Timer();
		timeout.schedule(new TimerTask() {
			@Override
			public void run() {
				cleanupSessions();
			}
		}, 1, timeoutTime);
		logg.info("Sessions Manager initialized!");
	}

	protected static void cleanupSessions() {
		logg.warn("Cleanup started!");
		int count = 0;
		Set<Long> keys = sessionsMap.keySet();
		for (Long ID : keys) {
			if (timeoutMap.get(ID) == null) {
				logg.warn("Bad timeout data for id: " + ID);
				timeoutMap.remove(ID);
				sessionsMap.remove(ID);
				// permissionsMap.remove(ID);
			} else if (timeoutMap.get(ID)) {
				logg.info("Session " + ID + " for user " + sessionsMap.get(ID) + " removed becouse of timeout");
				count++;
				Vector<Long> vec = new Vector<>();
				vec.add(ID);
				vec.add(sessionsMap.get(ID));
				destroySession(vec);
			} else {
				timeoutMap.put(ID, true);
			}

		}
		logg.info("Cleanup finished, removed: " + count + " sessions becouse of timeout \n" + sessionsMap.values().size() + " open connections");
	}

	/**
	 * 
	 * @param loginAndPassword
	 *            first login, second password
	 * @return
	 */
	public synchronized static CCSession createSession(String login, CCLoginDataDTO user) {
		logg.info("Creating new session for: " + login);
		CCSession newSession = null;
		// CCLoginDataDTO user = checkLoginData(loginAndPassword.get(0), loginAndPassword.get(1));
		if (user != null) {
			if (!sessionsMap.contains(user.getId())) {
				newSession = new CCSession(generateSessionID(), login, user.getId());
				sessionsMap.put(newSession.getSessionID(), newSession.getUserID());
				timeoutMap.put(newSession.getSessionID(), false);
				// permissionsMap.put(newSession.getSessionID(),
				// user.getPermissions());
			}
		}
		return newSession;
	}

	/**
	 * 
	 * @param sessionAndUserID
	 *            first session ID, second user ID
	 */
	public synchronized static void destroySession(Vector<Long> sessionAndUserID) {
		if (sessionsMap.contains(sessionAndUserID.get(1)) && sessionsMap.get(sessionAndUserID.get(0)).equals(sessionAndUserID.get(1))) {
			sessionsMap.remove(sessionAndUserID.get(0));
			// permissionsMap.remove(sessionAndUserID.get(0));
			timeoutMap.remove(sessionAndUserID.get(0));
		}
	}

	public static boolean checkSession(Long sessionID) {
		if (sessionsMap.get(sessionID) != null) {
			timeoutMap.put(sessionID, false);
			return true;
		} else if (sessionID == 0) {
			return true;
		}
		return false;
	}

	// public static boolean checkSession(Long sessionID, Long userID) {
	// timeoutMap.put(sessionID, false);
	// return sessionsMap.get(sessionID).equals(userID);
	// }

	// public static CCPermissions getPermissions(Long sessionID) {
	// if (checkSession(sessionID)) {
	// return permissionsMap.get(sessionID);
	// }
	// return null;
	// }

	private synchronized static long generateSessionID() {
		if (lastSessionID < 0)
			lastSessionID = 1;
		return lastSessionID++;
	}

}
